
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h> 
#include <sys/resource.h> 
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/mman.h>
#include "../../../libavcodec/avcodec.h"
#include "favc_avcodec.h"
#include "ratecontrol.h"

//#define DEBUG_IN_FILE
//#define DEBUG_OUT_FILE
//#define USE_MMAP
//#define OUTPUT_BITSTREAM_SIZE_FILE
//#define SHOW_PERFORMANCE_EVALUATION_RESULT

  
#define	FAVC_DECODER_DEV  "/dev/f264dec"
#define	FAVC_ENCODER_DEV  "/dev/f264enc"

int         favc_dec_fd=0;
int         favc_enc_fd=0;
static int  favc_quant=0;

#ifdef USE_MMAP
static int dec_mmap_addr,enc_mmap_addr;
#endif

#ifdef DEBUG_OUT_FILE
char dout_name[30];
FILE *dout;
#endif

#ifdef DEBUG_IN_FILE
char din_name[30];
FILE *din;
#endif

FAVC_MD_INFO h264_mval;
static H264_RateControl h264_ratec;
static int frm_cnt;

//################## Performance evaluation function #######################//
#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
#include <sys/time.h>
typedef unsigned long long uint64;

static void time_start(struct timeval *tv)
{	
      gettimeofday (tv, NULL);
}

static uint64 time_delta(struct timeval *start, struct timeval *stop)
{
      uint64 secs, usecs;

      secs = stop->tv_sec - start->tv_sec;
      usecs = stop->tv_usec - start->tv_usec;
      if (usecs < 0) {
        secs--;
        usecs += 1000000;
      }
      return secs * 1000000 + usecs;
}

static uint64 time_stop(struct timeval *begin)
{
      struct timeval end;
      gettimeofday (&end, NULL);
      return time_delta (begin, &end);
}
#endif
//################## H.264 decoder AVCodec #######################//

typedef struct AVCDecContext {
#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    uint64  nsecs;
    struct  timeval t1;
    int     pic_count;  
#endif        
} AVCDecContext;


int favc_decoder_init(AVCodecContext *avctx)
{
    int                 ret_value;
    AVCDecContext       *s = avctx->priv_data;	
    FAVC_DEC_PARAM      tDecParam;
    
#if (OUTPUT_FMT == OUTPUT_FMT_YUV)
    avctx->pix_fmt= PIX_FMT_YUV420P;
#else
#if (OUTPUT_FMT == OUTPUT_FMT_YUV422)  
    avctx->pix_fmt= PIX_FMT_YUV422;
#else
    avctx->pix_fmt= PIX_FMT_RGB555;
#endif
#endif      

	avctx->flags |=	CODEC_FLAG_PICT_ALLOC_EXTERNAL;

	if(favc_dec_fd==0)
	    favc_dec_fd=open(FAVC_DECODER_DEV,O_RDWR);

	if(favc_dec_fd<=0)
	{
	    printf("Fail to open %s\n",FAVC_DECODER_DEV);
	    return -1;
	}

#ifdef DEBUG_OUT_FILE
    sprintf(dout_name,"/tmp/out%d.yuv",getpid());
    dout=fopen(dout_name,"wb");
    printf("Use decoder output name %s\n",dout_name);
#endif

#ifdef DEBUG_IN_FILE
    sprintf(din_name,"/tmp/in%d.264",getpid());
    din=fopen(din_name,"wb");
    printf("Use decoder input name %s\n",din_name);
#endif

#ifdef USE_MMAP
    dec_mmap_addr=(int)mmap(0,(avctx->framebuffer_rgb_stride*avctx->framebuffer_rgb_height*3)/2,PROT_READ|PROT_WRITE,MAP_SHARED,favc_dec_fd, 0);
    if(dec_mmap_addr<=0)
        return -1;
//    printf("mmap_addr=0x%x\n",dec_mmap_addr);
#endif
	
//	tDecParam.u32API_version = 0x00020002;
	tDecParam.u32MaxWidth	= avctx->width;
	tDecParam.u32MaxHeight = avctx->height;
	tDecParam.u32FrameBufferWidth = avctx->framebuffer_rgb_stride;
	tDecParam.u32FrameBufferHeight = avctx->framebuffer_rgb_height;

	ret_value=ioctl(favc_dec_fd,FAVC_IOCTL_DECODE_INIT,&tDecParam);
	if(ret_value<0)
	{
	    printf("FAVC_IOCTL_DECODE_INIT: memory allocation failed\n");
	    return -1;
	}

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    s->pic_count = 0;
    time_start(&(s->t1));
#endif	
	return 0;
}	


int favc_decode(AVCodecContext *avctx, void *data, int *got_picture, uint8_t *buf, int buf_size)
{
    AVCDecContext       *s=avctx->priv_data;	
    AVFrame             *picture=(AVFrame *)data;
    FAVC_DEC_PARAM      tDecParam;
    int                 ret_value;

#ifdef DEBUG_IN_FILE
    fwrite((void *)buf,buf_size,1,din);fflush(din);
#endif

//printf("Decode one frame buf=0x%x size=%d display 0x%x 0x%x 0x%x\n",buf,buf_size,picture->data[0],picture->data[1],picture->data[2]);fflush(stdout);
	//getchar();
	
	// set display virtual addr (YUV or RGB)
	tDecParam.pu8Display_addr[0] = (unsigned int)picture->data[0];
	tDecParam.pu8Display_addr[1] = (unsigned int)picture->data[1];
	tDecParam.pu8Display_addr[2] = (unsigned int)picture->data[2];
	tDecParam.u32Pkt_size =	(unsigned int)buf_size;
	tDecParam.pu8Pkt_buf = (unsigned int)buf;
	
	if((ret_value = ioctl(favc_dec_fd,FAVC_IOCTL_DECODE_FRAME,&tDecParam))<0)
	{
	    *got_picture = 0;		
	    printf("FAVC_IOCTL_DECODE_FRAME: Failed.\n");
		return -1;
	}

	*got_picture=tDecParam.got_picture;

#ifdef DEBUG_OUT_FILE
    fwrite((void *)picture->data[0],avctx->width*avctx->height,1,dout);
    fwrite((void *)picture->data[1],avctx->width*avctx->height/4,1,dout);
    fwrite((void *)picture->data[2],avctx->width*avctx->height/4,1,dout);
#endif

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    s->pic_count++;
#endif 

    return buf_size;
}

int favc_decoder_end(AVCodecContext *avctx)
{
    AVCDecContext *s = avctx->priv_data;
        	    

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    s->nsecs = time_stop(&(s->t1)) / 1000;
    printf("\nspend %lld milliseconds with toal frame count %d = %f(frames/per second)\n", s->nsecs,s->pic_count,(float)((float)s->pic_count)/((float)s->nsecs/(float)1000.0)); fflush(stdout);
    printf("h264 decoding is done. %d frames are encoded\n",s->pic_count);	
#endif

#ifdef USE_MMAP
    munmap((void *)dec_mmap_addr,(avctx->framebuffer_rgb_stride*avctx->framebuffer_rgb_height*3)/2);
#endif
    
    if(favc_dec_fd)
        close(favc_dec_fd);
    favc_dec_fd=0;
    return 0;
}		



//################## H.264 encoder AVCodec #######################//

typedef struct FH264EncContext_TAG {
    unsigned char *mdinfo;	
    FAVC_MD_INFO *mdcfg;	
#ifdef OUTPUT_BITSTREAM_SIZE_FILE
    FILE *out_bitstream_size_file;
#endif

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    unsigned int        pic_count;
    uint64              nsecs;
    struct              timeval t1;
#endif    
} FH264EncContext;

#define WORK_FRMS  32
#define jpg_out_filename "/tmp/264_alarm"
void favc_set_motion_cfg(FAVC_MD_INFO *val)
{
    memcpy(&h264_mval,val,sizeof(FAVC_MD_INFO));
}

void favc_motion_info_init(FAVC_MD_INFO *motion)
{
         motion->pid = h264_mval.pid;
	motion->x0_LU = h264_mval.x0_LU;
  	motion->y0_LU = h264_mval.y0_LU;
  	motion->x0_RD = h264_mval.x0_RD;
  	motion->y0_RD = h264_mval.y0_RD;
  	motion->x1_LU = h264_mval.x1_LU;
  	motion->y1_LU = h264_mval.y1_LU;
  	motion->x1_RD = h264_mval.x1_RD;
  	motion->y1_RD = h264_mval.y1_RD;
  	motion->x2_LU = h264_mval.x2_LU;
  	motion->y2_LU = h264_mval.y2_LU;
  	motion->x2_RD = h264_mval.x2_RD;
  	motion->y2_RD = h264_mval.y2_RD;

  	motion->mv_th0 = h264_mval.mv_th0; 
  	motion->sad_th0 = h264_mval.sad_th0;   
         motion->alarm_idx0 = h264_mval.alarm_idx0;
		 
	motion->mv_th1 = h264_mval.mv_th1; 
  	motion->sad_th1 = h264_mval.sad_th1; 
         motion->alarm_idx1 = h264_mval.alarm_idx1;
		 
	motion->mv_th2 = h264_mval.mv_th2; 
  	motion->sad_th2 = h264_mval.sad_th2; 
         motion->alarm_idx2 = h264_mval.alarm_idx2;                           
		 
  	motion->interval = h264_mval.interval;  	
  	motion->enable = h264_mval.enable;
	motion->rotate = h264_mval.rotate; 
         motion->rotate_idx = h264_mval.rotate_idx;
	motion->frameindex = 0;	 
	
	#if 0
	printf("===== FH264 Motion Detection Configuration =====\n");
	printf("enable %d PID %d\n",motion->enable, motion->pid);
         printf("interval md %d rotate %d\n",  motion->interval, motion->rotate);       
	
	printf("area 0 [ %d , %d ] ~ [ %d , %d ] \n",
		motion->x0_LU, motion->y0_LU,
		motion->x0_RD, motion->y0_RD);
         printf("  threshold mv %d sad %d alarm_idx %d\n",
		motion->mv_th0,
		motion->sad_th0, motion->alarm_idx0);
		 
	printf("area 1 [ %d , %d ] ~ [ %d , %d ] \n",
		motion->x1_LU, motion->y1_LU,
		motion->x1_RD, motion->y1_RD);
	printf("  threshold mv %d sad %d alarm_idx %d\n",
		motion->mv_th1,
		motion->sad_th1, motion->alarm_idx1);
	
	printf("area 1 [ %d , %d ] ~ [ %d , %d ]\n",
		motion->x2_LU, motion->y2_LU,
		motion->x2_RD, motion->y2_RD);
         printf("  threshold mv %d sad %d alarm_idx %d\n",
		motion->mv_th2,
		motion->sad_th2, motion->alarm_idx2);
	#endif
}	  

extern int fmjpeg_encoder_sj(int width,int height,char *data0,char *data1,char *data2, char *outfile);
void favc_hw_enc_jpg(char *filename, char *dataY, char *dataU, char *dataV, int w, int h) 
{
	char oname[30];
    	char wi[10],hi[10],quant[10];
    	int len;
    
    	sprintf(wi,"%d",w);
    	sprintf(hi,"%d",h);
    	sprintf(quant,"256");
    	strcpy(oname,filename);
    	len=strlen(oname);
    	oname[len-1]='g';
    	oname[len-2]='p';
    	oname[len-3]='j';
	//printf("filename:%s\n",filename);
	//printf("do_Static_JPEG:%s\n",oname);
	if ( fmjpeg_encoder_sj( w, h, dataY, dataU, dataV, oname) < 0 )
		 printf("error to encode\n");

}


void favc_sw_enc_jpg(char *filename,int w,int h)
{
    char oname[30];
    char wi[10],hi[10],quant[10];
    int len;
    
    sprintf(wi,"%d",w);
    sprintf(hi,"%d",h);
    sprintf(quant,"256");
    strcpy(oname,filename);
    len=strlen(oname);
    oname[len-1]='g';
    oname[len-2]='p';
    oname[len-3]='j';
    
    if(execlp("yuv2jpg","yuv2jpg",filename,oname,wi,hi,quant,(char *)0)<0)
	    printf("error to execle\n");
}

//void do_alarm(char *filename,pid_t alarm_pid,int w,int h)
void favc_do_alarm(char *filename,pid_t alarm_pid,int w,int h,char *data0,char *data1,char *data2)
{
    pid_t gpid;

    if((gpid=fork())<0)
        printf("fork error");
    else if(gpid==0)
    {
        //favc_sw_enc_jpg(filename,w,h);
        favc_hw_enc_jpg(filename,data0,data1,data2,w,h);
        exit(0);
    }

    if(waitpid(gpid,NULL,0)<0)
        printf("wait error");

    remove(filename);
    if(alarm_pid!=0)
    {
        kill(alarm_pid,SIGALRM);
        //printf("Send signal SIGALRM to process %d\n",alarm_pid);
    }
}

void favc_motion_alarm_action(FAVC_MD_RESULT *enc_frame, FAVC_MD_INFO   *motion, int width,int height,char *data0,char *data1,char *data2)
{
    unsigned char   filename[30];
    pid_t           gpid;

    if( (frm_cnt % motion->interval ) == 0 )   {
	    if((enc_frame->active0>motion->alarm_idx0)||(enc_frame->active1>motion->alarm_idx1)||(enc_frame->active2>motion->alarm_idx2))     {
	        printf("\n<Motion Dection Alarm (%d,%d,%d)!>\n",enc_frame->active0,enc_frame->active1,enc_frame->active2);
	        sprintf(filename,"%s%02d.yuv", jpg_out_filename,motion->rotate_idx);
	        if(motion->rotate_idx>=motion->rotate)
	            motion->rotate_idx=1;
	        else
	            motion->rotate_idx++;
                 frm_cnt = WORK_FRMS+1;	
                 if((gpid=fork())<0)
                     printf("fork error");
	        else if(gpid==0)      {
                     favc_do_alarm(filename,gpid,width,height,data0,data1,data2);
                     exit(0);
                 }
	        if(waitpid(gpid,NULL,0)<0)
	            printf("wait error");
             }
    }
}
int favc_encoder_init(AVCodecContext *avctx)
{
    FAVC_ENC_PARAM     enc_param;
    FH264EncContext     *s = (FH264EncContext *)avctx->priv_data;
    
#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    time_start(&(s->t1));
    s->pic_count = 0;
#endif
    
    if(favc_enc_fd==0)
      favc_enc_fd=open(FAVC_ENCODER_DEV,O_RDWR);
	                       
    if(favc_enc_fd<=0)
    {
      printf("Fail to open %s\n",FAVC_ENCODER_DEV);
      return -1;
    }

#ifdef DEBUG_OUT_FILE
    sprintf(dout_name,"/tmp/out%d.264",getpid());
    dout=fopen(dout_name,"wb");
    printf("Use encoder output name %s\n",dout_name);
#endif
    
#ifdef DEBUG_IN_FILE
    sprintf(din_name,"/tmp/in%d.yuv",getpid());
    din=fopen(din_name,"wb");
    printf("Use encoder input name %s\n",din_name);
#endif

#ifdef USE_MMAP
    enc_mmap_addr=(int)mmap(0,(avctx->width*avctx->height*3)/2,PROT_READ|PROT_WRITE,MAP_SHARED,favc_enc_fd, 0);
    if(enc_mmap_addr<=0)
        return -1;
    printf("mmap addr=0x%x\n",enc_mmap_addr);fflush(stdout);
#endif
   
    enc_param.u32FrameWidth = avctx->width;
    enc_param.u32FrameHeight = avctx->height;
    enc_param.fFrameRate = (float)avctx->frame_rate/(float)avctx->frame_rate_base;
    enc_param.u32IPInterval = avctx->fh264_ip;
    enc_param.u32Quant = avctx->fh264_quant;
	enc_param.u32MaxQuant       =avctx->qmax;
	enc_param.u32MinQuant       =avctx->qmin;
    enc_param.u32BitRate        = avctx->bit_rate;

    s->mdinfo = s->mdcfg = NULL;
    if ( h264_mval.enable==1) {
	s->mdinfo=malloc( SYSBUF_SIZE(avctx->width, avctx->height) );
        	if(s->mdinfo==NULL)    {
        		printf("Can't allocate memory for MACROBLOCK_INFO!\n");
        		return -1;
        	}
	s->mdcfg = malloc(sizeof(FAVC_MD_INFO) );
	if(s->mdcfg==NULL)    {
        		printf("Can't allocate memory for motion!\n");
        		return -1;
        	}
	favc_motion_info_init(s->mdcfg);
	if ( s->mdcfg->interval == 0)
		s->mdcfg->interval = enc_param.fFrameRate;
	frm_cnt=0;
    }	
    /* rate control */
    H264RateControlInit(&h264_ratec,(float)enc_param.u32BitRate,(float)enc_param.fFrameRate,
        enc_param.u32FrameWidth,enc_param.u32FrameHeight,enc_param.u32IPInterval,
        enc_param.u32MaxQuant,enc_param.u32MinQuant,enc_param.u32Quant);
    
    ioctl(favc_enc_fd,FAVC_IOCTL_ENCODE_INIT,&(enc_param));
    avctx->coded_frame= avcodec_alloc_frame();
    avctx->coded_frame->key_frame=1;
    
#ifdef OUTPUT_BITSTREAM_SIZE_FILE
    s->out_bitstream_size_file = fopen("output_bitstream_size.txt","w");
#endif

    return 0;
}

#define abs(X)    (((X)>0)?(X):-(X))
#define mb(x)	(x/16)
void favc_motion_dection(
		unsigned char *mb_array, 
		FAVC_MD_INFO   *md_info, 
		FAVC_MD_RESULT   *md_res, 
		unsigned int mbwidth, 
		int mbheight)
{
    	unsigned int x_pos, y_pos;
	unsigned int sad16=0;
	unsigned int mv0_x, mv0_y, mv1_x, mv1_y;
    	unsigned char*mb;
		
	//if ( (md_info->frameindex >= md_info->interval) && (md_info->frameindex>WORK_FRMS)  ) {
		for(y_pos=0 ; y_pos<mbheight; y_pos++ ) {	
         	     for ( x_pos=0 ; x_pos<mbwidth ; x_pos++ ) {
			mb=(unsigned char *)(mb_array+(y_pos*mbwidth + x_pos)*64);
			mv0_x = mv0_x_value(mb);
			mv0_y = mv0_y_value(mb);
			mv1_x = mv1_x_value(mb);
			mv1_y = mv1_y_value(mb);
			sad16 = sad_hb_value(mb)<<8 + sad_lb_value(mb);
	    		if( (x_pos >= md_info->x0_LU ) && (y_pos >= md_info->y0_LU )
				&&(x_pos < md_info->x0_RD ) && (y_pos < md_info->y0_RD) ) {
				if (  ((mv0_x*mv0_x +  mv0_y*mv0_y) > (md_info->mv_th0*md_info->mv_th0) )
					&& ( (mv1_x*mv1_x +  mv1_y*mv1_y) > (md_info->mv_th0*md_info->mv_th0) )
					&& (sad16 > md_info->sad_th0) ) {
					md_res->active0++;
				}
				/*
				fprintf(stdout,"pos[%d,%d] mv0 [%d, %d] mv1[%d, %d] sad %d\n",
					x_pos, y_pos,
					mv0_x, mv0_y,
					mv1_x, mv1_y,
					sad16);
				*/	
			}
				
			if((x_pos >= md_info->x1_LU)  && (y_pos >= md_info->y1_LU )
				&&(x_pos < md_info->x1_RD) && (y_pos < md_info->y1_RD) ){
				if (  ((mv0_x*mv0_x +  mv0_y*mv0_y) > (md_info->mv_th1*md_info->mv_th1)) 
					&& ( (mv1_x*mv1_x +  mv1_y*mv1_y) > (md_info->mv_th1*md_info->mv_th1)) 
					&& (sad16 > md_info->sad_th1) ) {
					md_res->active1++;
				}
			}
			if((x_pos >= md_info->x2_LU) && (y_pos >= md_info->y2_LU )
				&&(x_pos < md_info->x2_RD) && (y_pos < md_info->y2_RD) ){
				if (  ((mv0_x*mv0_x +  mv0_y*mv0_y) > (md_info->mv_th2*md_info->mv_th2) )
					&& ( (mv1_x*mv1_x +  mv1_y*mv1_y) > (md_info->mv_th2*md_info->mv_th2) )
					&& (sad16 > md_info->sad_th2 ) ) {
					md_res->active2++;
				}
			}
		  }
    	     }
	//}	
}

void favc_get_mb_info(unsigned char *mdinfo)
{
	if ( ioctl(favc_enc_fd,FAVC_IOCTL_GET_SYSINFO,mdinfo) < 0) 	{
	    printf("Error to set FAVC_IOCTL_GET_SYSINFO\n");
	    return;
	}
}

int favc_encode(AVCodecContext *avctx, unsigned char *frame, int buf_size, void * data)
{
    FH264EncContext     *s=(FH264EncContext *)avctx->priv_data;
    FAVC_ENC_PARAM      enc_param;
    AVFrame             *pav = (AVFrame *)data;
    FAVC_MD_RESULT md_res;

#ifdef DEBUG_IN_FILE
    if(pav->data[0]!=0)
    {
        fwrite((void *)pav->data[0],(avctx->width*avctx->height*3)/2,1,din);
    }
#endif
    
    // set display virtual addr (YUV or RGB)
#ifdef USE_MMAP
    {
        int y_sz,uv_sz;
        y_sz=(avctx->width*avctx->height);
        uv_sz=(avctx->width*avctx->height)/4;
        if(pav->data[0]!=0)
        {
            memcpy((char *)enc_mmap_addr,pav->data[0],y_sz);
            memcpy((char *)enc_mmap_addr+y_sz,pav->data[1],uv_sz);
            memcpy((char *)enc_mmap_addr+y_sz+uv_sz,pav->data[2],uv_sz);
            enc_param.pu8YFrameBaseAddr = (unsigned char *)enc_mmap_addr;
            enc_param.pu8UFrameBaseAddr = (unsigned char *)enc_mmap_addr+y_sz;
            enc_param.pu8VFrameBaseAddr = (unsigned char *)enc_mmap_addr+y_sz+uv_sz;
            msync(enc_mmap_addr,y_sz+uv_sz+uv_sz,MS_ASYNC);
        }
        else
        {
            enc_param.pu8YFrameBaseAddr = 0;
            enc_param.pu8UFrameBaseAddr = 0;
            enc_param.pu8VFrameBaseAddr = 0;
        }
    }
#else
    enc_param.pu8YFrameBaseAddr = (unsigned char *)pav->data[0];
    enc_param.pu8UFrameBaseAddr = (unsigned char *)pav->data[1];
    enc_param.pu8VFrameBaseAddr = (unsigned char *)pav->data[2];
#endif

    enc_param.bitstream = frame;

//printf("favc_encode buf Y=0x%x U=0x%x V=0x%x bitstream=0x%x ",(unsigned int)enc_param.pu8YFrameBaseAddr,(unsigned int)enc_param.pu8UFrameBaseAddr,(unsigned int)enc_param.pu8VFrameBaseAddr,enc_param.bitstream);fflush(stdout);
   
    favc_quant=enc_param.u32Quant=H264RateControlGetQuant(&h264_ratec); 
//printf("quant=%d\n",favc_quant);
    if ( ioctl(favc_enc_fd,FAVC_IOCTL_ENCODE_FRAME,&enc_param) < 0 ) {
	printf("Error to set FAVC_IOCTL_ENCODE_FRAME\n");
	return;	
    }

    H264RateControlUpdate(&h264_ratec,enc_param.bitstream_size,enc_param.frame_cost);
    frm_cnt++;
    if((h264_mval.enable==1)&&(pav->data[0]!=0))  {  //motion dection enable
         
	 //if(((s->mdcfg->frameindex%s->mdcfg->interval)==0)&&(s->mdcfg->frameindex>WORK_FRMS))    {
          if(frm_cnt>WORK_FRMS)    {
		 	
		int mb_width,mb_height; 
		//do motion detection
		md_res.active0=0;
		md_res.active1=0;
		md_res.active2=0;
		
		mb_width=(avctx->width+15)/16;
         	mb_height=(avctx->height+15)/16;
     	        	favc_get_mb_info(s->mdinfo);
		favc_motion_dection(s->mdinfo, s->mdcfg, &md_res, mb_width, mb_height);
         	fprintf(stdout,"[%d %d %d %d ]\n", frm_cnt, md_res.active0, md_res.active1, md_res.active2);
		fflush(stdout);	 
         	favc_motion_alarm_action(&md_res,s->mdcfg, avctx->width,avctx->height,pav->data[0],pav->data[1],pav->data[2]);
	}
	
    }	
    
    pav->key_frame = enc_param.keyframe;

#ifdef DEBUG_OUT_FILE
    fwrite((void *)frame,enc_param.bitstream_size,1,dout);
#endif

#ifdef OUTPUT_BITSTREAM_SIZE_FILE
    fprintf(s->out_bitstream_size_file,"%08x\n",enc_param.bitstream_size);
#endif

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    s->pic_count++;
#endif

    return enc_param.bitstream_size;
}


int favc_encoder_end(AVCodecContext *avctx)
{
    FH264EncContext *s = (FH264EncContext *)avctx->priv_data;
	
    if( s->mdinfo)
	free(s->mdinfo);	
    if ( s->mdcfg )
	free(s->mdcfg);
	
    if(favc_enc_fd)
    {
#ifdef USE_MMAP
        munmap((void *)enc_mmap_addr,(avctx->width*avctx->height*3)/2);
#endif
        close(favc_enc_fd);
    }
    favc_enc_fd=0;
    
#ifdef DEBUG_OUT_FILE
    fclose(dout);
#endif

#ifdef DEBUG_IN_FILE
    fclose(din);
#endif

#ifdef OUTPUT_BITSTREAM_SIZE_FILE
    fclose(s->out_bitstream_size_file);
#endif

#ifdef SHOW_PERFORMANCE_EVALUATION_RESULT
    s->nsecs = time_stop(&(s->t1)) / 1000;
    printf("spend %lld milliseconds with toal frame count %d = %f(frames/per second)\n", s->nsecs,s->pic_count,(float)((float)s->pic_count)/((float)s->nsecs/(float)1000.0));
    printf("h264 encoding is done. %d frames are encoded\n",s->pic_count);
#endif
    
    return 0;
}

AVCodec favc_decoder = {
    "fh264",
    CODEC_TYPE_VIDEO,
    CODEC_ID_H264,		// need check
    sizeof(AVCDecContext),
    favc_decoder_init,
    NULL,			// encode
    favc_decoder_end,		// close
    favc_decode,		// decode
    0				// capabilities
};

AVCodec favc_encoder = {
    "fh264",
    CODEC_TYPE_VIDEO,
    CODEC_ID_H264,		// need check
    sizeof(FH264EncContext),
    favc_encoder_init,
    favc_encode,                // encode
    favc_encoder_end,		// close
    NULL,  		        // decode
    0				// capabilities
};

int H264RateControlGetQ(void)
{
    return favc_quant;
}
